package com.victor.lib.core.rotate;

import com.victor.lib.core.*;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.*;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

public class RotateLoading extends Component implements Component.EstimateSizeListener, Component.DrawTask {

    private static final int DEFAULT_WIDTH = 6;
    private static final int DEFAULT_SHADOW_POSITION = 2;
    private static final int DEFAULT_SPEED_OF_DEGREE = 10;

    private Paint mPaint;

    private RectFloat loadingRectF;
    private RectFloat shadowRectF;

    private int topDegree = 10;
    private int bottomDegree = 190;

    private float arc;

    private int width;

    private boolean changeBigger = true;

    private int shadowPosition;

    private boolean isStart = false;

    private int color;

    private int speedOfDegree;

    private float speedOfArc;

    private Context mContext;

    public RotateLoading(Context context) {
        super(context);
        this.mContext = context;
        addDrawTask(this);
        initView(context, null);
    }

    public RotateLoading(Context context, AttrSet attrs) {
        super(context, attrs);
        this.mContext = context;
        addDrawTask(this);
        initView(context, attrs);
    }

    public RotateLoading(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        addDrawTask(this);
        initView(context, attrs);
    }

    private void initView(Context context, AttrSet attrs) {
        color = Color.WHITE.getValue();
        width = (int) DensityUtil.dip2px(context, DEFAULT_WIDTH);
        shadowPosition = (int) DensityUtil.dip2px(context, DEFAULT_SHADOW_POSITION);
        speedOfDegree = DEFAULT_SPEED_OF_DEGREE;
        if (null != attrs) {
            if (attrs.getAttr("loading_color").isPresent()) {
                color = attrs.getAttr("loading_color").get().getDimensionValue();
            } else {
                color = Color.WHITE.getValue();
            }
            if (attrs.getAttr("loading_width").isPresent()) {
                width = attrs.getAttr("loading_width").get().getDimensionValue();
            } else {
                width = (int) DensityUtil.dip2px(context, DEFAULT_WIDTH);
            }
            if (attrs.getAttr("shadow_position").isPresent()) {
                shadowPosition = attrs.getAttr("shadow_position").get().getDimensionValue();
            } else {
                shadowPosition = DEFAULT_SHADOW_POSITION;
            }
            if (attrs.getAttr("loading_speed").isPresent()) {
                speedOfDegree = attrs.getAttr("loading_speed").get().getDimensionValue();
            } else {
                speedOfDegree = DEFAULT_SPEED_OF_DEGREE;
            }
        }
        speedOfArc = speedOfDegree / 4;
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setStrokeWidth(width);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);

        width = 15;
        int w = 240;
        int h = 240;
        int shadowPosition = 2;

        loadingRectF = new RectFloat(2 * width, 2 * width, w - 2 * width, h - 2 * width);
        shadowRectF = new RectFloat(2 * width + shadowPosition, 2 * width + shadowPosition, w - 2 * width + shadowPosition, h - 2 * width + shadowPosition);
    }


    public void setLoadingColor(int color) {
        this.color = color;
    }

    public int getLoadingColor() {
        return color;
    }

    public void start() {
        startAnimator();
        isStart = true;
        invalidate();
    }

    public void stop() {
        stopAnimator();
        invalidate();
    }

    public boolean isStart() {
        return isStart;
    }

    public void setLoadingRenderer() {
        addDrawTask(this);
    }

    private void startAnimator() {
        loading();
        AnimatorProperty animator = this.createAnimatorProperty();
        animator.scaleX(1f);
        animator.scaleY(1f);
        animator.setDuration(500);
        animator.start();
    }

    private void stopAnimator() {
        AnimatorProperty animator = this.createAnimatorProperty();
        animator.scaleX(0f);
        animator.scaleY(0f);
        animator.setDuration(500);
        animator.start();
    }

    EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());
    private DataAnimatorValue endValue;
    private DataAnimatorValue startValue;

    private void loading() {
        if (startValue == null) {
            startValue = makeValueAnimator(0, 360);
        } else {
            if (!startValue.isRunning()) {
                startValue.start();
            }
        }
        if (endValue == null) {
            endValue = makeEndValueAnimator(30, 60, 120, 90, 60, 30);
        } else {
            if (!endValue.isRunning()) {
                endValue.start();
            }
        }
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                loading();
                invalidate();
            }
        }, 10);
    }

    private DataAnimatorValue makeValueAnimator(float... value) {
        DataAnimatorValue valueAnimator = new DataAnimatorValue();
        valueAnimator.setStart(value[0]);
        valueAnimator.setEnd(value[1]);
        valueAnimator.setCurveType(Animator.CurveType.LINEAR);
        valueAnimator.setDuration(200);
        valueAnimator.start();
        return valueAnimator;
    }

    private DataAnimatorValue makeEndValueAnimator(float... value) {
        DataAnimatorValue value1 = new DataAnimatorValue();
        value1.setStart(30);
        value1.setEnd(60);
        value1.setDuration(200);

        DataAnimatorValue value2 = new DataAnimatorValue();
        value2.setStart(60);
        value2.setEnd(120);
        value2.setDuration(200);

        DataAnimatorValue value3 = new DataAnimatorValue();
        value3.setStart(120);
        value3.setEnd(90);
        value3.setDuration(200);

        DataAnimatorValue value4 = new DataAnimatorValue();
        value4.setStart(90);
        value4.setEnd(60);
        value4.setDuration(200);

        DataAnimatorValue value5 = new DataAnimatorValue();
        value5.setStart(60);
        value5.setEnd(30);
        value5.setDuration(200);

        value1.setStateChangedListener(new AnimatorChangeListener(value2));
        value2.setStateChangedListener(new AnimatorChangeListener(value3));
        value3.setStateChangedListener(new AnimatorChangeListener(value4));
        value4.setStateChangedListener(new AnimatorChangeListener(value5));
        value5.setStateChangedListener(new AnimatorChangeListener(value1));
        return value1;
    }


    class AnimatorChangeListener implements Animator.StateChangedListener {
        DataAnimatorValue nextAnimator;

        public AnimatorChangeListener(DataAnimatorValue nextAnimator) {
            this.nextAnimator = nextAnimator;
        }

        @Override
        public void onStart(Animator animator) {
        }

        @Override
        public void onStop(Animator animator) {
        }

        @Override
        public void onCancel(Animator animator) {
        }

        @Override
        public void onEnd(Animator animator) {
            nextAnimator.start();
            endValue = nextAnimator;
        }

        @Override
        public void onPause(Animator animator) {
        }

        @Override
        public void onResume(Animator animator) {
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!isStart) {
            return;
        }

        LogUtil.error("RotateLoading: ", "onDraw: ");

        topDegree += speedOfDegree;
        bottomDegree += speedOfDegree;
        if (topDegree > 360) {
            topDegree = topDegree - 360;
        }
        if (bottomDegree > 360) {
            bottomDegree = bottomDegree - 360;
        }

        if (changeBigger) {
            if (arc < 160) {
                arc += speedOfArc;
                invalidate();
            }
        } else {
            if (arc > speedOfDegree) {
                arc -= 2 * speedOfArc;
                invalidate();
            }
        }
        if (arc >= 160 || arc <= 10) {
            changeBigger = !changeBigger;
            invalidate();
        }

        Arc arcDataX = new Arc();
        Arc arcDataY = new Arc();
        arcDataX.setArc(topDegree, arc, false);
        arcDataY.setArc(bottomDegree, arc, false);
        mPaint.setColor(new Color(RgbPalette.parse("#1a000000")));
        canvas.drawArc(shadowRectF, arcDataX, mPaint);
        canvas.drawArc(shadowRectF, arcDataY, mPaint);

        mPaint.setColor(new Color(color));
        canvas.drawArc(loadingRectF, arcDataX, mPaint);
        canvas.drawArc(loadingRectF, arcDataY, mPaint);
    }

    @Override
    public boolean onEstimateSize(int w, int h) {
        arc = 10;
        loadingRectF = new RectFloat(2 * width, 2 * width, w - 2 * width, h - 2 * width);
        shadowRectF = new RectFloat(2 * width + shadowPosition, 2 * width + shadowPosition, w - 2 * width + shadowPosition, h - 2 * width + shadowPosition);

        LogUtil.error("RotateLoading: ", "onEstimateSize: loadingRectF--" + loadingRectF);
        LogUtil.error("RotateLoading: ", "onEstimateSize: shadowRectF--" + shadowRectF);
        return true;
    }
}
